# -*- coding: utf-8 -*-
import time, os
from core import logger
from typing import List, Dict

from config.config import config
from core.dataClasses import Event
from core.securitySelection import SecuritySelection, SecuritySelectionMultiprocessing
from core.enums import DateFormat, Period, EventType
from event.event_manager import EventManager
from tactic.chan import ChanTactic, ChanTacticSelectionOption
from core import threadLocal

# 上证50
sh50 = [
    "688981.SH", "688599.SH", "688111.SH", "688041.SH", "603986.SH", "603799.SH", "603501.SH", "603288.SH",
    "603259.SH", "601988.SH", "601919.SH", "601899.SH", "601888.SH", "601857.SH", "601728.SH", "601669.SH",
    "601668.SH", "601633.SH", "601628.SH", "601601.SH", "601398.SH", "601390.SH", "601318.SH", "601288.SH",
    "601225.SH", "601166.SH", "601088.SH", "601012.SH", "600905.SH", "600900.SH", "600893.SH", "600887.SH",
    "600809.SH", "600690.SH", "600519.SH", "600438.SH", "600436.SH", "600406.SH", "600309.SH", "600276.SH",
    "600150.SH", "600111.SH", "600104.SH", "600089.SH", "600050.SH", "600048.SH", "600036.SH", "600031.SH",
    "600030.SH", "600028.SH",
]
# 深证50
sz50 = [
    "000002.SZ", "000063.SZ", "000100.SZ", "000333.SZ", "000338.SZ", "000538.SZ", "000568.SZ", "000625.SZ",
    "000651.SZ", "000661.SZ", "000725.SZ", "000786.SZ", "000792.SZ", "000858.SZ", "000938.SZ", "000963.SZ",
    "000977.SZ", "001979.SZ", "002001.SZ", "002027.SZ", "002179.SZ", "002180.SZ", "002230.SZ", "002271.SZ",
    "002311.SZ", "002352.SZ", "002371.SZ", "002415.SZ", "002460.SZ", "002466.SZ", "002475.SZ", "002493.SZ",
    "002555.SZ", "002594.SZ", "002714.SZ", "002920.SZ", "300003.SZ", "300012.SZ", "300015.SZ", "300059.SZ",
    "300122.SZ", "300124.SZ", "300274.SZ", "300308.SZ", "300408.SZ", "300498.SZ", "300750.SZ", "300760.SZ",
    "300896.SZ", "300979.SZ",
]
hs300 = [
    '600023.SH', '000786.SZ', '000999.SZ', '000983.SZ', '601898.SH', '600011.SH', '601699.SH', '600188.SH',
    '601088.SH', '601872.SH', '003816.SZ', '600795.SH', '603392.SH', '601919.SH', '000425.SZ', '600025.SH',
    '000408.SZ', '601985.SH', '601225.SH', '600886.SH', '688041.SH', '688271.SH', '603993.SH', '600489.SH',
    '002001.SZ', '600085.SH', '000338.SZ', '002555.SZ', '600018.SH', '002648.SZ', '000157.SZ', '600900.SH',
    '600015.SH', '601808.SH', '600219.SH', '600019.SH', '600362.SH', '600150.SH', '603260.SH', '601857.SH',
    '300979.SZ', '601607.SH', '601100.SH', '000708.SZ', '300760.SZ', '601006.SH', '001289.SZ', '002603.SZ',
    '300498.SZ', '601009.SH', '600660.SH', '002714.SZ', '600332.SH', '601989.SH', '600028.SH', '601328.SH',
    '600875.SH', '601618.SH', '601939.SH', '601288.SH', '600016.SH', '600547.SH', '600089.SH', '601988.SH',
    '601229.SH', '601169.SH', '000876.SZ', '600803.SH', '600989.SH', '601111.SH', '601916.SH', '600039.SH',
    '600760.SH', '000538.SZ', '600674.SH', '601899.SH', '000768.SZ', '601336.SH', '601398.SH', '000617.SZ',
    '601600.SH', '601601.SH', '601021.SH', '601998.SH', '002179.SZ', '600346.SH', '600919.SH', '601818.SH',
    '600905.SH', '601117.SH', '688256.SH', '601211.SH', '600031.SH', '605499.SH', '688981.SH', '000333.SZ',
    '600029.SH', '601390.SH', '601877.SH', '601766.SH', '600938.SH', '000661.SZ', '600515.SH', '600000.SH',
    '300408.SZ', '601238.SH', '688126.SH', '601186.SH', '600754.SH', '601669.SH', '000301.SZ', '000651.SZ',
    '600111.SH', '000800.SZ', '601868.SH', '600176.SH', '600837.SH', '000895.SZ', '600426.SH', '600999.SH',
    '601816.SH', '000776.SZ', '600893.SH', '600233.SH', '002466.SZ', '601236.SH', '601878.SH', '002938.SZ',
    '600196.SH', '600010.SH', '601658.SH', '000100.SZ', '601838.SH', '601728.SH', '600061.SH', '600941.SH',
    '600372.SH', '000725.SZ', '600115.SH', '601800.SH', '301269.SZ', '002311.SZ', '601698.SH', '600104.SH',
    '600036.SH', '002493.SZ', '603195.SH', '300413.SZ', '600585.SH', '603019.SH', '002916.SZ', '600741.SH',
    '600406.SH', '600690.SH', '002202.SZ', '601377.SH', '300433.SZ', '600584.SH', '002736.SZ', '600918.SH',
    '002241.SZ', '601628.SH', '601788.SH', '600606.SH', '000792.SZ', '002475.SZ', '300033.SZ', '688303.SH',
    '002601.SZ', '300124.SZ', '601615.SH', '601668.SH', '600030.SH', '600309.SH', '600438.SH', '601688.SH',
    '000166.SZ', '600926.SH', '600436.SH', '300999.SZ', '601319.SH', '600276.SH', '688223.SH', '300919.SZ',
    '688187.SH', '300059.SZ', '300751.SZ', '000733.SZ', '300142.SZ', '600887.SH', '600009.SH', '002007.SZ',
    '000977.SZ', '688363.SH', '000001.SZ', '603288.SH', '603486.SH', '601995.SH', '688008.SH', '002142.SZ',
    '601799.SH', '601059.SH', '600570.SH', '300223.SZ', '300308.SZ', '600050.SH', '002049.SZ', '601318.SH',
    '600958.SH', '600745.SH', '000963.SZ', '000877.SZ', '300763.SZ', '600460.SH', '688396.SH', '600588.SH',
    '002371.SZ', '600732.SH', '300122.SZ', '601881.SH', '601633.SH', '600183.SH', '002074.SZ', '601901.SH',
    '600519.SH', '688599.SH', '002180.SZ', '300759.SZ', '300496.SZ', '002236.SZ', '300274.SZ', '300628.SZ',
    '000069.SZ', '600845.SH', '603799.SH', '603986.SH', '300450.SZ', '601155.SH', '000938.SZ', '002460.SZ',
    '002594.SZ', '002415.SZ', '002230.SZ', '601066.SH', '002271.SZ', '300896.SZ', '002027.SZ', '002410.SZ',
    '000002.SZ', '002352.SZ', '002129.SZ', '601012.SH', '000858.SZ', '688561.SH', '603259.SH', '603806.SH',
    '300316.SZ', '300661.SZ', '603833.SH', '603659.SH', '603290.SH', '603369.SH', '300014.SZ', '000063.SZ',
    '002304.SZ', '601360.SH', '601865.SH', '688065.SH', '002812.SZ', '002709.SZ', '002459.SZ', '603501.SH',
    '000625.SZ', '002050.SZ', '300347.SZ', '000596.SZ', '688036.SH', '000568.SZ', '300015.SZ', '002841.SZ',
    '601888.SH', '600132.SH', '002821.SZ', '600600.SH',
]
custom = [
    "000063.SZ"  # 中兴通讯
]


def chanSecuritySelection(securities: List[str], period:Period = Period.day, mode: int = 1) -> List[str]:
    """
    缠 日线 买点检测
    :param period: 分析周期
    :param mode: 模式：1：买点检测（检测下跌背驰） 0： 卖点检测（检测上涨背驰）
    :return:
    """
    threadLocal.add("threadName", "test")
    chanTactic = ChanTactic()
    chanTactic.mode = mode
    chanTactic.setPeriod(period=period)
    securitySelection = SecuritySelection()
    securitySelection.setTactic(chanTactic)
    securitySelection.addSecurities(securities)
    return securitySelection.__run()


def day_30m_chan(securities: List[str], mode: int = 1) -> List[str]:
    """
    日线和30分钟线共振
    :param securities:
    :param mode: 模式：1：买点检测（检测下跌背驰） 0： 卖点检测（检测上涨背驰）
    :return:
    """
    result = chanSecuritySelection(securities, period=Period.day, mode=mode)
    if result is None or len(result) == 0:
        return []
    result = chanSecuritySelection(result, period=Period.minute30, mode=mode)
    if result is None or len(result) == 0:
        result = []
    logger.error(f"日K      -{'买点' if mode==1 else '卖点'}: {','.join([s[:-3] for s in result])}")
    logger.error(f"30分钟K线 -{'买点' if mode==1 else '卖点'}: {','.join([s[:-3] for s in result])}")
    return result


def multiMonitor(securities: List[str]):
    import multiprocessing

    def getData(lock, shareDict: Dict[str, List[str]], period: Period):
        l = len(shareDict[period.name])
        for i in range(l):
            yield shareDict[period.name][i]
            if i == l - 1:
                i = 0

    def popData(lock, shareDict: Dict[str, List[str]], period: Period):
        with lock:
            if len(shareDict[period.name]) > 0:
                return shareDict[period.name].pop()

    def addData(lock, shareDict: Dict[str, List[str]], period: Period, security: str):
        with lock:
            if security not in shareDict[period.name]:
                shareDict[period.name].append(security)

    class DataEventHander:
        def __init__(self, lock, shareDict: Dict[str, List[str]]):
            self.lock = lock
            self.shareDict: Dict[str, List[str]] = shareDict

        def __call__(self, event: Event):
            if event.type == EventType.TACTIC_MONITOR:
                with self.lock:
                    self.shareDict[event.data[1].name].append(event.data[0])

    def selection(lock, shareDict: Dict[str, List[str]], period:Period, getFun, addFun, selectionOption: ChanTacticSelectionOption):
        name = "test"
        threadLocal.add("threadName", name)
        event_manager:EventManager = EventManager.getInstance(name=name)

        dataEventHander = DataEventHander(lock, shareDict)
        event_manager.addEventListener(eventType=EventType.TACTIC_MONITOR, handler=dataEventHander)
        chanTactic = ChanTactic()
        chanTactic.selectionOption = selectionOption
        chanTactic.setPeriod(period=period)
        securitySelection = SecuritySelectionMultiprocessing()
        securitySelection.getter = getFun
        securitySelection.lock = lock
        securitySelection.shareDict = shareDict
        securitySelection.period = period
        securitySelection.setTactic(chanTactic)
        securitySelection.addSecurities(securities)
        securitySelection.__run()

    def monitor(lock, shareDict: Dict[str, List[str]]):
        while(True):
            logger.error(f"待操作股票列表：{str(shareDict[Period.minute5.name])}")
            time.sleep(1)


    manager = multiprocessing.Manager()
    shareDict = manager.dict()
    lock = manager.Lock()
    shareDict[Period.day.name] = securities
    shareDict[Period.minute30.name] = []
    shareDict[Period.minute5.name] = []
    selectionOption_day = ChanTacticSelectionOption(trend="-", deviateStatus=1, deviateDegree=0, eventType=EventType.TACTIC_MONITOR, nextPeriod=Period.minute30)
    selectionOption_m30 = ChanTacticSelectionOption(trend="-", deviateStatus=1, deviateDegree=0, eventType=EventType.TACTIC_MONITOR, nextPeriod=Period.minute5)
    pDay = multiprocessing.Process(target=selection, args=(lock, shareDict, Period.day, getData,  selectionOption_day))
    pM30 = multiprocessing.Process(target=selection, args=(lock, shareDict, Period.minute30, popData, selectionOption_day))
    pmonitor= multiprocessing.Process(target=monitor, args=(lock, shareDict, Period.minute30, popData, selectionOption_day))
    pDay.start()
    pM30.start()
    pmonitor.start()


if __name__ == "__main__":
    logPath = config.get("logger", "log_path")
    format = config.get("logger", "format")
    logger.add(os.path.join(logPath, 'runtime_{time}.log'), level="INFO", format=format, rotation="1 day",
               retention='3 days', compression='zip')
    logger.add(os.path.join(logPath, 'ssuccess_{time}.log'), level="SUCCESS", format=format, rotation="1 day",
               retention='3 days', compression='zip')
    logger.add(os.path.join(logPath, 'error_{time}.log'), level="ERROR", format=format, rotation="1 day",
               retention='3 days', compression='zip')
    securities = []

    # 上证50+深证50+沪深300
    securities = securities + sh50
    securities = securities + sz50
    # securities = securities + hs300

    # 沪深300-上证50-深证50
    # securities = hs300 - sh50 - sz50

    securities = list(set(securities))

    # securities = day_30m_chan(securities, mode=1)
    multiMonitor(securities)